package com.ltkj.pay.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.ltkj.common.core.constant.HttpStatus;
import com.ltkj.common.core.domain.R;
import com.ltkj.common.core.utils.DateUtils;
import com.ltkj.common.core.web.controller.BaseController;
import com.ltkj.common.core.web.domain.AjaxResult;
import com.ltkj.common.security.annotation.RequiresPermissions;
import com.ltkj.common.security.utils.SecurityUtils;
import com.ltkj.pay.config.WechatPayConfig;
import com.ltkj.pay.config.WechatPayRequest;
import com.ltkj.pay.domain.TicPayLog;
import com.ltkj.pay.domain.TicPayRefundLog;
import com.ltkj.pay.service.ITicPayLogService;
import com.ltkj.pay.service.ITicPayRefundLogService;
import com.ltkj.system.api.RemoteOrderService;
import com.ltkj.system.api.RemoteWxUserService;
import com.ltkj.system.api.domain.TicOrder;
import com.ltkj.system.api.domain.WxUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.*;

/**
 * @Author gushaoliang
 * @Date 2023/9/12 14:48
 * @PackageName:com.ltkj.pay.controller
 * @ClassName: PayController
 * @Description: 支付
 * @Version 1.0
 */

@Api(tags = "支付模块")
@RestController
@RequestMapping("/pay")
public class PayController extends BaseController {


    @Resource
    private WechatPayConfig wechatPayConfig;

    @Resource
    private WechatPayRequest wechatPayRequest;

    @Autowired
    private RemoteOrderService remoteOrderService;
    @Autowired
    private RemoteWxUserService remoteWxUserService;
    @Autowired
    private ITicPayLogService ticPayLogService;
    @Autowired
    private ITicPayRefundLogService ticPayRefundLogService;
    /**
     * 预支付订单生成入口
     */
    @ApiOperation("预支付订单生成入口")
    @GetMapping("/transactions/{orderId}")
    public AjaxResult transactions(@PathVariable("orderId")Long orderId) {


        R<TicOrder> wxPayInfo = remoteOrderService.getWxPayInfo(orderId);
        if(wxPayInfo.getCode()!= HttpStatus.SUCCESS){
            return AjaxResult.error("此订单不存在");
        }
        Long userid = SecurityUtils.getLoginUser().getUserid();
        R<WxUser> userInfo = remoteWxUserService.getUserInfo(userid);
        if(userInfo.getCode()!= HttpStatus.SUCCESS){
            return AjaxResult.error("此用户不存在");
        }
        WxUser data = userInfo.getData();
        String openid=data.getOpenid();
        TicOrder ticOrder = wxPayInfo.getData();
        if(ticOrder==null){
            return AjaxResult.error("此订单不存在");
        }
        if(!ticOrder.getOrderStatus().equals("1")){
            return AjaxResult.error("此订单已支付不能重新支付");
        }

        // 统一参数封装
        Map<String, Object> params = new HashMap<>(10);
        // 1,appid：公众号或移动应用的唯一标识符。
        params.put("appid", wechatPayConfig.getAppId());
        // 2,mch_id：商户号，由微信支付分配。
        params.put("mchid", wechatPayConfig.getMchId());
        // 3.description body：商品描述。

        params.put("description", ticOrder.getOrderNum());
        // 4.out_trade_no：商户订单号，由商户自定义。
        params.put("out_trade_no", ticOrder.getWxOrderNum());
        // 5.notify_url：接收微信支付异步通知回调地址。
        params.put("notify_url", wechatPayConfig.getNotifyUrl());
        // 6.total_fee：订单总金额，单位为分。
        Map<String, Object> amountMap = new HashMap<>(4);
        // 金额单位为分
        BigDecimal total = ticOrder.getOrderTotalPrice();
        Integer integer = total.intValue();
        amountMap.put("total",  integer);
        amountMap.put("currency", "CNY");
        params.put("amount", amountMap);


        // 7.openid：用户在商户appid下的唯一标识。
        Map<String, Object> payerMap = new HashMap<>(4);
        // openid  需要前端小程序通过用户code 请求微信接口获取用户唯一openid  不懂的看官方文档：https://developers.weixin.qq.com/doc/aispeech/miniprogram/quickuse.html
        payerMap.put("openid", openid);
        params.put("payer", payerMap);

        String paramsStr = JSON.toJSONString(params);
        logger.info("请求参数 ===> {}" + paramsStr);

        // 微信预支付下单接口路径
        String payUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        // 获取支付 prepay_id参数
        String resStr = wechatPayRequest.wechatHttpOrderPost(payUrl, paramsStr);


        Map<String, Object> resMap = JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>() {
        });
        Object prepayId = resMap.get("prepay_id");

        UUID uuid = UUID.randomUUID();
        // 获取签名
        String paySign;
        try {
            StringBuilder sb = new StringBuilder();
            // 应用id
            sb.append(wechatPayConfig.getAppId()).append("\n");
            // 支付签名时间戳
            sb.append(System.currentTimeMillis() / 1000).append("\n");
            // 随机字符串

            sb.append(uuid).append("\n");
            // 预支付交易会话ID  这个要注意 key = "prepay_id=xxxxxx"
            sb.append("prepay_id=").append(prepayId).append("\n");
            // 签名
            Signature sign = Signature.getInstance("SHA256withRSA");
            // 获取商户私钥并进行签名
            PrivateKey privateKey = wechatPayConfig.getPrivateKey(wechatPayConfig.getKeyPemPath());
            sign.initSign(privateKey);
            sign.update(sb.toString().getBytes(StandardCharsets.UTF_8));
            // 得到签名
            paySign = Base64.getEncoder().encodeToString(sign.sign());
        } catch (Exception e) {
            logger.error("支付模块_生成交易签名失败！" + e.getMessage());
            return AjaxResult.error("系统异常！");
        }


        // 将签名时数据和签名一起返回前端用于前端吊起支付
        Map<String, Object> map = new HashMap<>();
        // 小程序id
        map.put("appId", wechatPayConfig.getAppId());
        // 时间戳
        map.put("timeStamp", System.currentTimeMillis() / 1000);
        // 随机字符串
        map.put("nonceStr", uuid);
        // 预支付交易会话ID
        map.put("package", "prepay_id=" + prepayId);
        // 签名方式
        map.put("signType", "RSA");
        // 签名
        map.put("paySign", paySign);


        try {
            TicPayLog ticPayLog = new TicPayLog();
            ticPayLog.setOrderId(orderId);
            ticPayLog.setUserId(userid);
            ticPayLog.setOpenId(openid);
            ticPayLog.setTotal(total);
            ticPayLog.setPayJson(paramsStr);
            ticPayLog.setOrderNum(ticOrder.getOrderNum());
            ticPayLog.setWxOrderNum(ticOrder.getWxOrderNum());
            ticPayLog.setCreateBy(SecurityUtils.getUsername());
            ticPayLog.setCreateTime(DateUtils.getNowDate());
            ticPayLog.setIsDel("0");
            ticPayLogService.insertTicPayLog(ticPayLog);
        } catch (NumberFormatException e) {
            logger.error(String.format("支付新增记录异常%s", e.getMessage()));
        }


        return  AjaxResult.success(map);
    }


    /**
     * 申请退款
     */
    @ApiOperation("申请退款")
    @RequiresPermissions("pay:refundOrder:refundOrder")
    @GetMapping("/refundOrder/{orderId}")
    public AjaxResult refundOrder(@PathVariable("orderId")Long orderId) {

        logger.info("根据订单号申请退款，订单号： {}", orderId);
        // 退款请求路径
        String url = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
        // 设置参数
        Map<String, Object> params = new HashMap<>(2);
        // 要退款的订单编号订单编号
        R<TicOrder> wxPayInfo = remoteOrderService.orderPayOrderIdDetail(orderId);
        logger.info(wxPayInfo.toString());
        if(wxPayInfo.getCode()!= HttpStatus.SUCCESS){
            return AjaxResult.error("此订单不存在");
        }

        TicOrder ticOrder = wxPayInfo.getData();
        if(ticOrder==null){
            return AjaxResult.error("此订单不存在");
        }
        R<WxUser> userInfo = remoteWxUserService.getUserInfo(ticOrder.getUserId());
        WxUser data = userInfo.getData();
        String openid=data.getOpenid();
        if(userInfo.getCode()!= HttpStatus.SUCCESS){
            return AjaxResult.error("此用户不存在");
        }
        if(ticOrder.getOrderStatus().equals("1")){
            return AjaxResult.error("此订单未支付不能退款");
        }
        if(ticOrder.getOrderStatus().equals("7")){
            return AjaxResult.error("此订单已在退款中!");
        }
        if(ticOrder.getOrderStatus().equals("6")){
            return AjaxResult.error("此订单已退款!");
        }
        if(ticOrder.getOrderStatus().equals("3")){
            return AjaxResult.error("此订单已取消!");
        }
        params.put("out_trade_no", ticOrder.getWxOrderNum());
        // 商户自定义退款记录单号 用于退款记录的单号 跟退款订单号不是一样的
        int outRefundNo = new Random().nextInt(999999999);
        logger.info("退款申请号：{}", outRefundNo);
        params.put("out_refund_no", outRefundNo + "");
        // 退款原因
        params.put("reason", "申请退款");
        // 退款通知回调地址
        params.put("notify_url", wechatPayConfig.getRefundNotifyUrl());

        Map<String, Object> amountMap = new HashMap<>();
        BigDecimal total = ticOrder.getOrderTotalPrice();
        //退款金额，单位：分
        Integer integer = total.intValue();
        amountMap.put("refund",  integer);
        //原订单金额，单位：分

        amountMap.put("total",  integer);
        //退款币种
        amountMap.put("currency", "CNY");
        params.put("amount", amountMap);
        String paramsStr = JSON.toJSONString(params);
        // todo 插入一条退款记录到数据库
        //退款记录
        try {
            TicPayRefundLog ticPayRefundLog = new TicPayRefundLog();
            ticPayRefundLog.setOrderId(orderId);
            ticPayRefundLog.setUserId(ticOrder.getUserId());
            ticPayRefundLog.setOpenId(openid);
            ticPayRefundLog.setTotal(total);
            ticPayRefundLog.setOutRefundNo(outRefundNo+"");
            ticPayRefundLog.setPayRefundJson(paramsStr);
            ticPayRefundLog.setOrderNum(ticOrder.getOrderNum());
            ticPayRefundLog.setWxOrderNum(ticOrder.getWxOrderNum());
            ticPayRefundLog.setCreateBy(SecurityUtils.getUsername());
            ticPayRefundLog.setCreateTime(DateUtils.getNowDate());
            ticPayRefundLog.setIsDel("0");
            ticPayRefundLogService.insertTicPayRefundLog(ticPayRefundLog);
        } catch (Exception e) {
            logger.error(String.format("退款申请新增记录异常%s", e.getMessage()));
        }
        logger.info("请求参数 ===> {}" + paramsStr);
        AjaxResult ajaxResult  = wechatPayRequest.wechatHttpPost(url, paramsStr);
        int code = (int) ajaxResult.get("code");
        if(code==HttpStatus.SUCCESS){
            AjaxResult ajaxResult1 = remoteOrderService.refundOrderStatus(orderId);
            logger.info("申请退款修改订单状态：{}", ajaxResult1);
        }
        logger.info("退款结果：{}", ajaxResult);
        return ajaxResult;
    }


}